#include <allegro.h>

#include <algorithm>
#include <string>
#include <vector>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;

#define FPS 30
#define MAX_Y 600
#define MAX_X 800

int rPadrao = 50;
int backg = 0;
int corFundo = 0xffff00;
int corEstado = 0xffffff;
int corAtivo = 0x777777;
int corTexto = 0;//0xffffff;
int corTransicao = 0xffffff;

typedef char Simbolo;

struct Ponto {
	int x, y;
	Ponto(){}
	Ponto(int x, int y): x(x), y(y) {}
	Ponto operator+(const Ponto b) const { return Ponto(x+b.x, y+b.y); }
	Ponto operator-() const { return Ponto(-x, -y); }
	Ponto operator-(const Ponto b) const { return *this+-b; }
	Ponto operator~() const { return Ponto(-y,x); }
	
	int operator*(const Ponto b) const { return x*b.x + y*b.y; }
	int operator%(const Ponto b) const { return x*b.y - y*b.x; }
	int operator!() const { return *this**this; }
	bool operator==(const Ponto b) const { return x == b.x && y == b.y; }
	
	Ponto norm(int d) {
		int sq = (int) sqrt(!*this);
		return Ponto(x*d/sq,y*d/sq);
	}
};


struct AF {
	struct Transicao {
		Simbolo simbolo;
		int origem, destino;
		AF * af;
		Transicao(){}
		Transicao(AF * af, Simbolo simbolo, int origem, int destino):
			af(af), simbolo(simbolo), origem(origem), destino(destino) {}
		
		void desenhar(BITMAP * bitmap) {
			Ponto orig = af->estados[origem].c;
			Ponto dest = af->estados[destino].c;
			if( orig == dest ) return;
			
			
			int delta = af->estados[origem].r; //5;
			Ponto dist = dest-orig;
			dist = ~dist.norm(delta);
			orig = orig + dist;
			dest = dest + dist;
			
			line(screen, orig.x, orig.y, dest.x, dest.y, corTransicao);
			// ponta da seta
		}
	};
	struct Estado {
		AF * af;
		char nome[80];
		Ponto c;
		int r;
		bool final, ativo;
		Estado() {}
		Estado(AF * af, const char * str, Ponto c, int r = rPadrao, bool final = false):
				af(af), c(c), r(r), final(final), ativo(false) {
			strcpy(nome,str);
		}
		
		void desenhar(BITMAP * bitmap) {
			if( ativo ) circlefill(bitmap, c.x,c.y,r, corAtivo);
			circle(bitmap, c.x,c.y,r, corEstado);
			if( final ) circle(bitmap, c.x,c.y,r-r/6, corEstado);
			textprintf_centre_ex(bitmap, font, c.x, c.y, corTexto, corFundo, "%s", nome);
		}
		bool operator==(const char * str) { return !strcmp(str,nome); }
	};
	
	char nome[80];
	vector<Estado> estados;
	vector<Transicao> transicoes;
	
	AF(const char * str) {
		strcpy(nome,str);
		criarEstado("Inicial", Ponto(rPadrao,rPadrao));
	}
	
	bool criarTransicao(Simbolo simb, int orig, int dest) {
		transicoes.push_back(Transicao(this,simb,orig,dest));
		return true;
	}
	bool criarEstado(const char * str, Ponto c, bool final = false, int r = rPadrao) {
		if( find(estados.begin(), estados.end(), str) != estados.end() ) return false;
		estados.push_back(Estado(this,str,c,r,final));
		return true;
	}
	
	void desenhar(BITMAP * bitmap) {
		textprintf_ex(bitmap, font, 0, 0, corTexto, corFundo, "%s", nome);
		for( int i = transicoes.size()-1 ; i >= 0 ; --i ) {
			transicoes[i].desenhar(bitmap);
		}
		for( int i = estados.size()-1 ; i >= 0 ; --i ) {
			estados[i].desenhar(bitmap);
		}
	}
	
	bool carregar(FILE * arq) {
		fgets(nome,80,arq);
		int ests, trans;
		fread(&ests, sizeof(int), 1, arq);
		fread(&trans, sizeof(int), 1, arq);
		estados.resize(ests);
		transicoes.resize(trans);
		fread(&estados.front(), sizeof(Estado), ests, arq);
		if(trans) fread(&transicoes.front(), sizeof(Transicao), trans, arq);
	}
	bool carregar(char * str) {
		FILE * arq = fopen(str,"r");
		carregar(arq);
		fclose(arq);
	}
	bool salvar(FILE * arq) {
		fputs(nome,arq);
		int ests = estados.size();
		int trans = transicoes.size();
		fwrite(&ests, sizeof(int), 1, arq);
		fwrite(&trans, sizeof(int), 1, arq);
		fwrite(&estados.front(), sizeof(Estado), ests, arq);	
		if(trans) fwrite(&transicoes.front(), sizeof(Transicao), trans, arq);
	}
	bool salvar(char * str) {
		FILE * arq = fopen(str,"w");
		salvar(arq);
		fclose(arq);
	}
	
};



int ticks = 0;
void ticker(){
	ticks++;
}
END_OF_FUNCTION(ticker);

void initAllegro() {
	allegro_init();
	install_keyboard();
	install_timer();
	LOCK_VARIABLE(ticks);
	LOCK_FUNCTION(ticker);
	install_int_ex(ticker, BPS_TO_TIMER(FPS));
	set_color_depth(32);
	set_gfx_mode(GFX_AUTODETECT_WINDOWED, MAX_X, MAX_Y, 0, 0);
	srand(time(NULL));
}


int main(){
	initAllegro();
	BITMAP *buffer = create_bitmap(MAX_X, MAX_Y);
	
	AF x("teste");
	x.criarEstado("E2", Ponto(100,100), true);
	x.criarTransicao('a', 0, 1);
	x.desenhar(screen);
	//circle( screen, x,y,r, 0xffffff);
	//line(screen, x0, y0, x1,y1, cor);
	rest(1000);
	//while(1);
	
	return 0;
}
END_OF_MAIN()

